package doc2db.fileWorker;


import doc2db.Keey;
import doc2db.table.*;
import java.io.PrintStream;
import java.util.List;
import java.util.ArrayList;
/**
 *
 * @author yuriy
 */
public class RefactorDublicateLongCell {
    /**список таблиц*/
    private List<DocTable> tables ;

    /** глубина заголовка в таблици (изменяется в ходе работы
        настоящее значение doc2db.Keey.headDepth*/
    private int toHead = 1;

    /**
     * Create new instance
     * @param tables table list to refactioring
     */
    public RefactorDublicateLongCell(List<DocTable> tables) {
        this.tables = tables;
    }

    /**
     * Определяет, по длине ячеек, сколько ячеек должно быть в каждой
     * строке таблици и разбивает длиные ячейки на несколько
     */
    public void refactoDublicateLongCell(){
        for (int iter = 0; iter < tables.size(); iter++) {
            DocTable tb = tables.get(iter);
            int NumCell = tb.getHead().get().length;

            DocTableBody body = tb.getBody();

            for (int i = 0; i < body.size(); i++) {
                if (body.getRowsSize(i) > NumCell) {
                    NumCell = body.getRowsSize(i);
                }
            }

//            System.err.println("num " + NumCell);
            tb = procTab(tb, NumCell);
            ((ArrayList)tables).set(iter, tb);
        }
    }

    /**
     *  Преобразовать неправильную таблицу, ячейки которой, в одном столбце,
     * могут иметь разную ширену, в правельную. Где в каждой строку будет
     * одинаковое число ячеек. Так же будет выдилена часть заголовка,
     * которая имеет древовидный вид.
     * @param tb Не правельная таблица
     * @param numCell Количество строк, которое предположительно относятся
     * к заголовку, но они не имеют значения, если пользователь явно указал
     * размер заголовка
     * @return Правельную таблицу
     */
    private DocTable procTab(DocTable tb, int numCell){
        toHead = 0;
        //2й правельный масив всех данных
        DocTableCell [][] cel = new DocTableCell[tb.getBody().size()][numCell];
        //таблица которую возварщаем
        DocTable retTab = tb;
        //номер строки, в 2м массиве, с максимальным количеством ячеек
        int idMaxNumCell = 0;
        //длина каждой ячейки в эталонной строке
        int etalonLen []  = new int [numCell];
        //количество ячеек в каждой строке таблицы
        int numElem[] = new int[tb.getBody().size()];

        //заголовок таблиц
        DocTableHead head = tb.getHead();
        //размер, вheadSIze ячейках, заголовка
        int headSize = head.getSize();


        //инициирует пустыми значениями 2й массив
        for (int i = 0; i < cel.length; i++) {
            for (int j = 0; j < cel[i].length; j++) {
                cel[i][j] = new DocTableCell();
            }
        }

        //в 0-ю строку 2го массива записываем данные из заголовка таблицы
        for (int i = 0; i < headSize; i++) {
            cel[0][i] = new DocTableCell(head.get(i));
        }

        //устанавливаем длину 0й строки, и номер строки с макс. кол. ячеек
        numElem[0] = headSize;
        numCell = 0;

        //тело таблицы
        final DocTableBody body = tb.getBody();

        //заполняем значениями массив
        for (int i = 0; i < body.size() - 1; i++) {
            final DocTableRows row = body.getRows(i);

            //устанавливаем длину i-й строки
            numElem[i + 1] = row.size();

            //задаём каждому элементу массива значение из таблицы
            for (int j = 0; j < row.size(); j++) {
                cel[i + 1][j] = new DocTableCell(row.getCell(j));
            }

            //если количество элементов в i-й строке больше чем ширена массива
            int sz = idMaxNumCell > 0 ? body.getRowsSize(idMaxNumCell - 1) : headSize;
            if (row.size() > sz) {
                //переустанавливаем значения идентификатора эталонной строки
                idMaxNumCell = i + 1;
            }
        }

        if (Keey.headDepth > 0) {
            toHead = Keey.headDepth;    //значение заданное пользователем
        } else {
            toHead = idMaxNumCell + 1;  //значение в массиве
        }

        //инициализируем єталоны длин в таблице
        for (int i = 0; i < cel[idMaxNumCell].length; i++) {
            etalonLen[i] = cel[idMaxNumCell][i].getLen();
        }

        System.out.println("REFACTOR:LINE-302: idMaxNumCell " + idMaxNumCell);
        System.out.println("REFACTOR:LINE-301: length " + etalonLen.length);

        //устанавливаем количество ячеек объедняемых ячейкой
        for (int i = 0; i < cel.length; i++) {
            int left = 0;   //длина которая осталась от прошлой колонки
            int len = cel[i].length;

            for (int j = 0, k = 0; j < len; j++) {
                int larg = cel[i][j].getLen() + left;
                //boolean last = (j + 1) >= len;//numElem[i];

                //cel[i][j].split = mdel(larg, etalonLen[j], last);
                //left = mmod(cel[i][j].getLen(), etalonLen[j]);

                int split = 0;
                left = larg;
                while (left > 0){
                    split ++;
                    int klen = 0;
                    try {
                        klen = etalonLen[k++];
                    } catch (Exception e) {
                        System.err.println(getClass().getCanonicalName() + "144:" + e);
                        System.err.println("\t Number of adding cell greate, " +
                                "then can be " + i + ":" + j);
                        split --;
                        break;
                    }
                    left = larg -= klen;
                    if (left < 0){
                        int l = Math.abs(left);
                        if (l * 0.7 >= etalonLen[k - 1]){
                            k--;
                            left += klen;
                            split --;
                        }
                    }
                }
                cel[i][j].split = split;
            }

        }

        //System.err.println("REFACTOR:LINE-324:");
        //soutArr(System.err, cel);
        //System.err.println("REFACTOR:LINE-325 : procTab- " + cel.length + " " + cel[0].length + " " + toHead);
        //System.exit(1);

        //разбиваем каждую ячейку на необходимое кол. под ячеек
        DocTableCell[][] normCel = toNormArr(cel, toHead);

        //преобразуем двойной массив ячеек в таблицу
        DocTable table = new DocTable();
        for (int i = 0; i < normCel[0].length; i++){
            table.addHeadCell(normCel[0][i]);
        }
        for (int i = 1; i < normCel.length; i++) {
            for (int j = 0; j < normCel[i].length; j++) {
                table.addBodyCell(normCel[i][j]);
            }
            table.addNewRow();
        }
        
        retTab = table;
        tb = table;

        return retTab;
    }

    private DocTableCell[][] toNormArr(DocTableCell c[][], int headLen){
        String sep = " | ";
        DocTableCell[][]  ret = new DocTableCell[c.length][];
        int maxlen = c[0].length;

        for (int i = 0; i < ret.length; i++) {
            ret[i] = to(c[i]);
            int rlen = ret[i].length;
            if (rlen > maxlen){
                maxlen = rlen;
            }
        }

        DocTableCell[][] retArr = new DocTableCell[c.length - headLen + 1][];
        retArr[0] = new DocTableCell[ret[0].length];

        for (int i = 0; i < retArr[0].length; i++) {
            retArr[0][i] = new DocTableCell(ret[0][i]);
        }

        for (int i = 1; i < headLen; i++) {
            for (int j = 0; j < retArr[0].length; j++) {
                retArr[0][j].setName(retArr[0][j].getName() + sep + ret[i][j].getName());
            }
        }

        for (int j = 0; j < retArr[0].length; j++) {
            retArr[0][j].setName(toShortName(retArr[0][j].getName(), 3, sep.trim()));
        }

        addIndex(retArr[0]);

        //soutArr(System.out, ret);
        for (int i = 1, j = headLen; i < retArr.length; i++, j++){
            retArr[i] = new DocTableCell[ret[j].length];
            for (int k = 0; k < retArr[i].length; k++) {
                retArr[i][k] = new DocTableCell(ret[j][k]);
                String name = retArr[0][k].getName();
                retArr[i][k].setHead(name);
            }
        }

        //soutArr(System.out, retArr);

        return retArr;
    }

    void soutArr(PrintStream out, DocTableCell [][] cell){
        out.println("ret[" + cell.length + "][?]:");
        for (int i = 0; i < cell.length; i++) {
            for (int j = 0; j < cell[i].length; j++) {
                out.println("    [" + i + "][" + j + "] = " + cell[i][j] + ";");
            }
            out.println();
        }
        out.flush();
    }

    private DocTableCell[] to (DocTableCell c[]){
        DocTableCell[][] ret = new DocTableCell[c.length][];
        int len = 0;
        for (int i = 0; i < ret.length; i++) {
            if (c[i].isZero()) {
                continue;
            }
            ret[i] = c[i].toCellArray();
            len += ret[i].length;
        }

        DocTableCell[] ret2 = new DocTableCell[len];
        for (int i = 0, j = 0; i < ret.length; i++) {
            if (ret[i] == null) {
                continue;
            }
            for (int k = 0; k < ret[i].length; k++) {
                ret2[j++] = new DocTableCell(ret[i][k]);
            }
        }

        return ret2;
    }

    private String toShortName(String longName, int step, String clean){
        if (longName.length() < 16) {
            return longName.toLowerCase();
        }

        StringBuffer ret = new StringBuffer();
        String arr[] = longName.split("\\s+");

        for (int i = 0; i < arr.length; i++) {
            if(arr[i].equals(clean)){
                ret.append("_");
                continue;
            }
            //ret.append(arr[i].substring(0, step));
            if(arr[i].length() > step){
                ret.append(arr[i].substring(0, step)).append("_");
            } //else if(arr[i].length() > 0){
            //    ret.append("" + arr[i].charAt(0) + "_");
            //}
            else {
                ret.append(arr[i]);
            }
        }
        String after = ret.toString().toLowerCase();
        System.out.println("before \"" + longName + "\"; after \"" + after + "\"");
        return after;
    }

    /**
     * If the array cells have a cell, with duplicate names,
     * to each added to them indexes
     * @param cels array of cells
     */
    private void addIndex(DocTableCell[] cels){
        for (int i = 0; i < cels.length; i++) {
            DocTableCell etalon = cels[i];
            int index = 0;
            for (int j = 0; j < cels.length; j++) {
                DocTableCell subcell = cels[j];
                String etalname = etalon.getName();
                String subname = subcell.getName();
                if ( i != j & etalname.equals(subname)){
                    subcell.setName(++index + subname);
                }
            }
        }
    }


}
